/*--------------------------------------------------------------------------------------*\
**
**			Heroes IV
**	  Copyright 2001, The 3DO Company
**
**      dialog_teleporter_entrance.cpp
**
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "dialog_teleporter_entrance.h"


#include "adaptor_handler.h"
#include "adventure_frame.h"
#include "adventure_map_window.h"
#include "army.h"
#include "basic_dialog.h"
#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer.h"
#include "bitmap_layer_window.h"
#include "bound_handler.h"
#include "buffer_window_ptr.h"
#include "button.h"
#include "button_cache.h"
#include "convert_16_bit.h"
#include "interface_help.h"
#include "mini_map_window.h"
#include "mouse_event.h"
#include "scrollbar.h"
#include "standard_fonts.h"
#include "table.h"
#include "table_ptr.h"
#include "text_window.h"

extern t_button_cache	g_ok_button;
extern t_button_cache   g_cancel_button;

namespace
{ // unnamed namespace
    t_bitmap_group_cache k_teleporter_bitmaps( "dialog.teleporter" );
    t_bitmap_group_cache k_teleporter_icons( "icons.teleporter" );

    const   int k_num_exit_windows = 3;

}; // unnamed namespace

/*----------------------------------------------------------------------------------*\
**
** Teleport mini-map class.
**
** Class derived from mini_map just to render
** for teleport mini-map.
**
\*----------------------------------------------------------------------------------*/
class t_mini_map_marker_window : public t_window, public t_mini_map_renderer
{
public:
	t_mini_map_marker_window( t_adventure_map const& map, t_screen_rect const& rect,
	               t_adventure_map_window* map_window, t_window* parent );

	virtual void         paint( t_paint_surface& paint_surface );
protected:
	void         center_view( t_screen_point point );
	// Member functions
	virtual t_shared_ptr< t_abstract_bitmap16 > create_back_buffer( t_screen_point const & size );
	virtual void on_rect_dirtied( t_screen_rect const & dirted_rect );
	virtual void on_size_change( t_screen_rect const& rect ); // in client coordinates of parent
	virtual void on_view_level_changed( int level );
	virtual void on_view_resized( t_screen_point const & size );

	t_counted_ptr<t_adventure_map_window>	m_map_window;
	t_shared_ptr<t_memory_bitmap16> m_back_buffer;
	bool m_dragging;
};

/*------------------------------------------------------------------------------------*\
**
** Constructer for teleporter mini-map.
**
\*------------------------------------------------------------------------------------*/
t_mini_map_marker_window::t_mini_map_marker_window( t_adventure_map const& map, t_screen_rect const& rect, 
		                              t_adventure_map_window* map_window, t_window* parent )
				 : t_window( k_no_transparency, parent), t_mini_map_renderer( map, map_window->get_frame()->get_team_view()),
				   m_map_window( map_window )
{
	init( rect );
	resize( rect.size() );
	m_dragging = false;
}

/*
** Teleporter mini-map.
*/
void t_mini_map_marker_window::paint( t_paint_surface& paint_surface )
{
	update( paint_surface.get_rect() );
	paint_surface.draw( t_screen_point(0,0), *m_back_buffer, m_back_buffer->get_rect() );
}

/*
** Teleporter mini-map.
*/
t_shared_ptr< t_abstract_bitmap16 > t_mini_map_marker_window::create_back_buffer(
													   t_screen_point const & size )
{
	m_back_buffer = new t_memory_bitmap16( size.x, size.y );
	return m_back_buffer;
}

void t_mini_map_marker_window::on_rect_dirtied( t_screen_rect const & rect )
{
	invalidate( rect );
}

/*
** Resize teleporter mini-map.
*/
void t_mini_map_marker_window::on_size_change( t_screen_rect const& rect )
{
	resize( rect.size() );
}

void t_mini_map_marker_window::on_view_level_changed( int level )
{
}

void t_mini_map_marker_window::on_view_resized( t_screen_point const & size )
{
}

void t_mini_map_marker_window::center_view( t_screen_point point )
{
	if (!m_dragging)
		return;
	t_screen_point map_size = get_adventure_map().get_view_size();
	t_screen_point mini_map_size = get_view_size();

	point.x = point.x * map_size.x / mini_map_size.x;
	point.y = point.y * map_size.y / mini_map_size.y;

	m_map_window->center_view( point );
}


/*---------------------------------------------------------------------------------------*\
**
** Teleporter dialog constructor.  Allow player to choose teleport exit, if more than 1.
**
\*---------------------------------------------------------------------------------------*/
t_dialog_teleporter_entrance::t_dialog_teleporter_entrance ( t_window* parent )
					: t_window( k_completely_transparent, parent )
{
}

void t_dialog_teleporter_entrance::init_dialog( t_adventure_frame* adventure_frame, t_level_map_point_2d_list exit_points, 
                std::vector<std::string> exit_names, int selected_exit, std::string const& name_text, std::string const& intro_text )
{
	t_bitmap_layer const*       layer;
	t_window *                  window;
	t_screen_point              origin(0,0);
	t_screen_point              point(0,0);
    int                         i;
	t_screen_rect               rect;
    t_adventure_map *           map_ptr = adventure_frame->get_map();
	t_adventure_map_window *    map_window_ptr = map_ptr->get_map_window();
	t_help_block const&		    shared_help = get_help_block( "shared" );

    m_mini_map_view_start_index = 0;

    // Just in case...should have at least 1 exit.  Assert if 0?
    if (exit_points.size() == 0)
    {
	    m_selected_exit = -1;
        return;
    }
        
    // Don't give choice if only 1 exit.
    if (exit_points.size() == 1)
    {
        // Selected exit is input.
	    m_selected_exit = selected_exit;
	    m_return_value = true;
        return;
    }

    m_selected_exit = 0;
    m_exit_names = exit_names;

    /*
    ** Bitmaps.
    */
	t_screen_point          frame_point(0,0);
	t_screen_point          frame_point_diff(0,0);
    
	m_bitmaps_ptr = k_teleporter_bitmaps.get();

	layer = m_bitmaps_ptr->find( "background" );
	window = new t_bitmap_layer_window( layer, origin, this );

	layer = m_bitmaps_ptr->find( "text_scroll" );
	window = new t_bitmap_layer_window( layer, origin, this );

	layer = m_bitmaps_ptr->find( "title_scroll" );
	window = new t_bitmap_layer_window( layer, origin, this );

	m_map_frame_layer = m_bitmaps_ptr->find( "mini_map_frame" );
   	rect = m_map_frame_layer->get_rect();
    frame_point = rect.top_left();
	m_map_frame_window = new t_bitmap_layer_window( m_map_frame_layer, origin, this );

   	rect = m_bitmaps_ptr->find( "mini_map_1" )->get_rect();
    frame_point_diff = frame_point - rect.top_left();
            
    /*
    ** Create buttons.
    */
	t_button            *button_ptr;
	rect = m_bitmaps_ptr->find( "ok_button" )->get_rect();
	button_ptr = new t_button( g_ok_button.get(), rect.top_left(), this );
	button_ptr->set_click_handler( bound_handler( *this, &t_dialog_teleporter_entrance::ok_click ));
  set_help( button_ptr, shared_help, "accept" );

	rect = m_bitmaps_ptr->find( "cancel_button" )->get_rect();
	button_ptr = new t_button( g_cancel_button.get(), rect.top_left(), this );
	button_ptr->set_click_handler( bound_handler( *this, &t_dialog_teleporter_entrance::close_click ));
  set_help( button_ptr, shared_help, "cancel" );

	m_exit_marker = m_bitmaps_ptr->find( "marker" );
	rect = m_exit_marker->get_rect();
	m_exit_marker->offset( -rect.top_left() );


    if ( exit_points.size() > k_num_exit_windows )
    {
        /*
        ** If more than k_num_exit_windows, give player a choice of exits.
        */
    	t_window_ptr            right_bar_window;
        
    	rect = m_bitmaps_ptr->find( "slide_bar" )->get_rect();
    	m_scrollbar = new t_scrollbar( rect.top_left(), rect.height(), this, 0, 0, true );
    	m_scrollbar->set_handler( bound_handler( *this, &t_dialog_teleporter_entrance::map_scrollbar_move));
    	m_scrollbar->set_position( 0 );
    	m_scrollbar->set_limits( 0, (exit_points.size()<k_num_exit_windows)?0:(exit_points.size()-k_num_exit_windows) );
    }

    /*
    ** Create windows.
    */
    char                map_name[128];
	t_text_window *     text_window_ptr;
    t_screen_point      map_size = map_ptr->get_view_size();
	t_mini_map_marker_window *   mini_map_ptr;

    m_screen_frame_points.clear();
    m_map_button_list.clear();
    
    /*
    ** Create windows to show exits in mini-maps.  Create buttons from mini-maps.
    */
    for (i=0; i < k_num_exit_windows; i++)
    {
        t_button *      map_button_ptr;
        double          mini_map_width = 0;
        double          mini_map_height = 0;

        // Get location on bitmap.
        sprintf ( map_name, "mini_map_%d", (i+1));
    	rect = m_bitmaps_ptr->find( map_name )->get_rect();

        mini_map_width = rect.width();
        mini_map_height = rect.height();

        point = rect.top_left();
        point += frame_point_diff;

        // Add point to list (so we know where to put the frame).
	    m_screen_frame_points.push_back ( point );

        // Create button holder.
		map_button_ptr = new t_button( rect.top_left(), this );

        m_map_button_list.push_back ( map_button_ptr );
        
        // Create map.
        rect -= rect.top_left();
    	mini_map_ptr = new t_mini_map_marker_window( *map_ptr, rect, adventure_frame->get_map_window(),
	    		                                map_button_ptr ); //right_bar_window );

        m_mini_map_list.push_back (mini_map_ptr);

        // Create teleporter exit marker.
    	window = new t_bitmap_layer_window( m_exit_marker, t_screen_point(0,0), mini_map_ptr );

        m_marker_window_list.push_back ( window );
        
	    map_button_ptr->enable( true );
	    map_button_ptr->update_size();
	    map_button_ptr->set_click_handler( add_2nd_argument( bound_handler( *this, &t_dialog_teleporter_entrance::map_clicked ), i));

        /*
        ** Text name.
        */
        sprintf ( map_name, "name_%d", (i+1));
    	rect = m_bitmaps_ptr->find( map_name )->get_rect();
    	text_window_ptr = new t_text_window( get_font( 22 ), rect, this, format_string( "" ), t_pixel_24(0,0,0));
    	text_window_ptr->set_center_horizontal();
    	text_window_ptr->set_drop_shadow( false );

	    m_exit_text_list.push_back ( text_window_ptr );
    }

    /*
    ** Convert exit points to mini-map points.
    */
    m_screen_exit_marker_points.clear();
    m_exit_level.clear();
	t_level_map_point_2d_list::const_iterator it;
    for (it = exit_points.begin(); it != exit_points.end(); it++)
    {
        /*
        ** Figure out location of marker (exit) on mini-map.
        */
	    t_level_map_point_2d    exit_position = *it;
        
	    m_exit_level.push_back( exit_position.level );

        // Use last mini_map_ptr... Center this later?
        rect = mini_map_ptr->get_tile_rect( exit_position );
        
	    m_screen_exit_marker_points.push_back ( rect.top_left() );
    }
    
    show_exits( m_mini_map_view_start_index );

    // Text windows.

	rect = m_bitmaps_ptr->find( "title" )->get_rect() + origin;
	text_window_ptr = new t_text_window( get_font( 22 ), rect, this, name_text, t_pixel_24(0,0,0));
	text_window_ptr->set_center_horizontal();
	text_window_ptr->set_drop_shadow( false );

	rect = m_bitmaps_ptr->find( "text" )->get_rect() + origin;
	text_window_ptr = new t_text_window( get_font( 20 ), rect, this, intro_text, t_pixel_24(0,0,0));
	text_window_ptr->set_center_horizontal();
	text_window_ptr->set_drop_shadow( false );

    /*
    ** Set the position (centered) and display the window.
    */
	t_screen_rect parent_rect = get_parent()->get_client_rect();
    
	rect = m_bitmaps_ptr->get_rect();
	rect += (parent_rect.size() - rect.size()) / 2;
	init( rect );
}

/*
** Update teleporter markers on mini-maps.
*/
void t_dialog_teleporter_entrance::show_exits( int start_index )
{
    m_mini_map_view_start_index = start_index;
    bool        more_exits_to_process = true;
    int         exit_index = start_index;
    int         counter = 0;

    while ( more_exits_to_process )
    {
        /*
        ** Location of marker (exit) on mini-map.
        */
	    t_screen_point          exit_point = m_screen_exit_marker_points[exit_index];

        m_marker_window_list[counter]->move (exit_point);
        m_map_button_list[counter]->enable( true );
        m_map_button_list[counter]->set_visible( true );
	    m_exit_text_list[counter]->set_text( m_exit_names[exit_index] );

	    m_mini_map_list[counter]->set_view_level ( m_exit_level[counter] );
        
        exit_index++;
        counter++;

        // Done?
        if ((counter >= k_num_exit_windows) || (counter == m_screen_exit_marker_points.size()))
        {
            more_exits_to_process = false;
        }
    }

    // Disable the rest of the maps, if any.
    if (counter < k_num_exit_windows)
    {
        m_map_button_list[counter]->enable( false );
        m_map_button_list[counter]->set_visible( false );
	    m_exit_text_list[counter]->set_text( "" );
        counter++;
    }
}

void t_dialog_teleporter_entrance::map_scrollbar_move( t_scrollbar* scrollbar, int value )
{
    m_mini_map_view_start_index = value;
    show_exits( m_mini_map_view_start_index );
}

int t_dialog_teleporter_entrance::get_selected_exit()
{
    return (m_selected_exit+m_mini_map_view_start_index);
}

void t_dialog_teleporter_entrance::left_button_down( t_mouse_event const& event )
{
}

// Clicked on a mini-map (teleporter exit).
void t_dialog_teleporter_entrance::map_clicked( t_button* button_ptr, int index )
{
	m_map_frame_window->move( m_screen_frame_points[index] );
	//m_map_frame_window->move( m_screen_exit_marker_points[index+m_mini_map_view_start_index] );
    m_selected_exit = index;
}

void t_dialog_teleporter_entrance::ok_click( t_button* button )
{
	m_return_value = true;
	close();
}

void t_dialog_teleporter_entrance::close_click( t_button* button )
{
    m_selected_exit = -1;
	m_return_value = false;
	close();
}

